<!DOCTYPE html>


<html lang="zh-CN">
  

    <head>
      <meta charset="utf-8" />
        
      <meta name="description" content="Java、MySql、Spring、JVM、虚拟机、数据库、Docker、Redis" />
      
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>深入理解JVM（七）Java类文件结构 |  ACEXS个人博客</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/blog-page/favicon.ico" />
       
<link rel="stylesheet" href="/blog-page/dist/main.css">

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css"
      />
      
<link rel="stylesheet" href="/blog-page/css/custom.css">
 
      <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    <link rel="alternate" href="/blog-page/atom.xml" title="ACEXS个人博客" type="application/atom+xml">
</head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-深入理解JVM（七）Java类文件结构"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  深入理解JVM（七）Java类文件结构
</h1>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/blog-page/2021/10/28/c045633ac839.html" class="article-date">
  <time datetime="2021-10-28T07:57:27.000Z" itemprop="datePublished">2021-10-28</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/blog-page/categories/%E8%AF%BB%E4%B9%A6%E6%88%90%E8%AF%97/">读书成诗</a> / <a class="article-category-link" href="/blog-page/categories/%E8%AF%BB%E4%B9%A6%E6%88%90%E8%AF%97/JVM/">JVM</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">4.4k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">16 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="类文件结构"><a href="#类文件结构" class="headerlink" title="类文件结构"></a>类文件结构</h1><p><strong>思想：</strong>一次编写，到处运行是Java诞生时提出的口号，因为操作系统平台的多样性，冲破平台之间的界限，变得尤为重要。字节码技术的实现，奠定了平台无关性的基础，随着技术的发展，语言无关性，也正在被开发者所重视，虚拟机和字节码技术称为语言无关性的基础。</p>
<p><strong>Class文件：</strong>是一组以8个字节为基础单位的二进制流，各个数据项严格按照顺序紧凑地排列在文件之中，中间没有添加任何分隔符。</p>
<p><em><strong>根据《Java虚拟机规范》规定，Class文件格式采用一种类似于C语言结构体的伪结构来存储数据，这种伪结构中只存在两种数据类型：无符号数和表。</strong></em></p>
<p><strong>无符号数：</strong>属于基本的数据类型，以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、8个字节的无符号数，可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。</p>
<p><strong>表：</strong>是由多个无符号数或者其他表作为数据项构成的复合数据类型。为了便于区分，所有表命名都以“_info”结尾。表用于描述有层次关系的复合结构的数据。整个Class文件本质上也可以看作一张表，表的数据项按照以下严格顺序排列构成。</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>名称</th>
<th>数量</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>u4</td>
<td>magic</td>
<td>1</td>
<td>魔数</td>
</tr>
<tr>
<td>u2</td>
<td>minor_version</td>
<td>1</td>
<td>次版本号</td>
</tr>
<tr>
<td>u2</td>
<td>major_version</td>
<td>1</td>
<td>主版本号</td>
</tr>
<tr>
<td>u2</td>
<td>constant_pool_cout</td>
<td>1</td>
<td>常量池数量</td>
</tr>
<tr>
<td>cp_info</td>
<td>constant_pool</td>
<td>constant_pool_count-1</td>
<td>常量池</td>
</tr>
<tr>
<td>u2</td>
<td>access_flags</td>
<td>1</td>
<td>访问标志</td>
</tr>
<tr>
<td>u2</td>
<td>this_class</td>
<td>1</td>
<td>类索引</td>
</tr>
<tr>
<td>u2</td>
<td>super_class</td>
<td>1</td>
<td>父类索引</td>
</tr>
<tr>
<td>u2</td>
<td>interfaces_count</td>
<td>1</td>
<td>接口索引数量</td>
</tr>
<tr>
<td>u2</td>
<td>interfaces</td>
<td>interfaces_count</td>
<td>接口索引集合</td>
</tr>
<tr>
<td>u2</td>
<td>fields_count</td>
<td>1</td>
<td></td>
</tr>
<tr>
<td>field_info</td>
<td>fields</td>
<td>fields_count</td>
<td></td>
</tr>
<tr>
<td>u2</td>
<td>methods_count</td>
<td>1</td>
<td></td>
</tr>
<tr>
<td>method_info</td>
<td>methods</td>
<td>methods_count</td>
<td></td>
</tr>
<tr>
<td>u2</td>
<td>attributes_count</td>
<td>1</td>
<td></td>
</tr>
<tr>
<td>attribute_info</td>
<td>attributes</td>
<td>attributes_count</td>
<td></td>
</tr>
</tbody></table>
<h2 id="魔数与版本号"><a href="#魔数与版本号" class="headerlink" title="魔数与版本号"></a>魔数与版本号</h2><p><strong>魔数：</strong>表中第一列u4，代表Class文件的头4个字节，称为魔数，是为了确定这个文件是否为一个能被虚拟机接受的Class文件。使用魔数区分文件而不使用拓展名，是基于安全考虑，文件拓展名可以随意改动，而魔数则是文件格式制定者选择的，没有被广泛采用过，不会引起混淆的值，对文件格式来说，更精确，更安全。</p>
<p><strong>Class文件的魔数值是：</strong>0xCAFEBABE</p>
<p><strong>版本号</strong></p>
<ul>
<li><strong>次版本号：</strong>表中第5、6个字节（第一个u2）表示次版本号。Java2时期被短暂引用过，后来版本中一直处于弃用状态（默认为0），JDK12时期，一些复杂新特性需要以“公测”形式放出，设计者重新启用次版本号，将它用于标识“技术预览版”。</li>
<li><strong>主版本号：</strong>表中第7、8个字节（第二个u2）表示主版本号。虚拟机可以兼容以前版本，但不能运行以后版本的Class文件，《Java虚拟机规范》Class文件校验部分明确要求了即使文件格式未发生任何变化，虚拟机也必须拒绝执行超过其版本号的Class文件。（从JDK9开始，javac编译器不再支持使用-source参数编译版本号小于1.5的源码）</li>
</ul>
<h2 id="常量池"><a href="#常量池" class="headerlink" title="常量池"></a>常量池</h2><p><strong>Class文件里的资源仓库。</strong></p>
<p><strong>结构：</strong>常量池入口防止一项u2类型的数据，代表常量池容量计数值，这个容量计数值从1开始。将0空出，是为了后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用热河一个常量池项目”的含义，可以把索引值设置为0来表示。</p>
<h3 id="存储数据"><a href="#存储数据" class="headerlink" title="存储数据"></a>存储数据</h3><h4 id="字面量"><a href="#字面量" class="headerlink" title="字面量"></a>字面量</h4><p>类似于Java语言中的常量，如文本字符串、被声明为final的常量值等。</p>
<h4 id="符号引用：编译原理方面的概念，包括下面几类常量："><a href="#符号引用：编译原理方面的概念，包括下面几类常量：" class="headerlink" title="符号引用：编译原理方面的概念，包括下面几类常量："></a>符号引用：编译原理方面的概念，包括下面几类常量：</h4><ul>
<li>被模块导出或开放的包。</li>
<li>类和接口的全限定名。</li>
<li>字段的名称和描述符。</li>
<li>方法的名称和描述符。</li>
<li>方法句柄和方法类型。</li>
<li>动态调用点和动态常量。</li>
</ul>
<p><strong>原理：</strong>Java代码在进行Javac编译时，不会进行“连接”这一步，而是虚拟机加载Class文件时候进行动态连接。Class文件中不会保存各个方法、字段最终在内存中的分布信息，这些字段、方法的符号引用不经过虚拟机在运行期间转换的话是无法得到真正的内存入口地址，也就无法直接被虚拟机使用。当虚拟机进行类加载时，将会从常量池获取对应的符号引用用，再在类创建时或运行时解析、翻译到具体内存地址之中。</p>
<h3 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a><a href="https://acexxs.gitee.io/blog-page/2021/11/01/a3fe09c36b43.html">数据结构</a></h3><p>常量池中每一项都是一个表，目前为止共有17种不同类型的常量，分别用来存储Class文件中的常量信息。</p>
<p>这17类表都有一个共同特点，表结构起始的第一位是个u1类型的标志位（tag）。</p>
<h2 id="访问标志"><a href="#访问标志" class="headerlink" title="访问标志"></a>访问标志</h2><p>2个字节，用于识别一些类或接口层次的访问信息。当前只定义了其中9个，没有用到的标志位一律为零。</p>
<table>
<thead>
<tr>
<th>标志名称</th>
<th>标志值</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>ACC_PUBLIC</td>
<td>0x0001</td>
<td>是否为public类型</td>
</tr>
<tr>
<td>ACC_FINAL</td>
<td>0x0010</td>
<td>是否声明为final，只有类可以设置</td>
</tr>
<tr>
<td>ACC_SUPER</td>
<td>0x0020</td>
<td>是否允许使用invokespecial字节码指令的新语义，invokespecial指令的语义在JDK1.0.2发生过改变，为了区别这条指令使用哪条语义，JDK1.0.2之后编译出来的类的这个标志都必须为真</td>
</tr>
<tr>
<td>ACC_INTERFACE</td>
<td>0x0200</td>
<td>标识这是一个接口</td>
</tr>
<tr>
<td>ACC_ABSTRACT</td>
<td>0x0400</td>
<td>是否是abstact类型，对于接口或抽象类来说，此标志为真，其他类型值为假</td>
</tr>
<tr>
<td>ACC_SYNTHETIC</td>
<td>0x1000</td>
<td>标志这个类并非由用户代码产生的</td>
</tr>
<tr>
<td>ACC_ANNOTATION</td>
<td>0x2000</td>
<td>标志这是一个注解</td>
</tr>
<tr>
<td>ACC_ENUM</td>
<td>0x4000</td>
<td>标志这是一个么据</td>
</tr>
<tr>
<td>ACC_MODULE</td>
<td>0x8000</td>
<td>标志这是一个模块</td>
</tr>
</tbody></table>
<h2 id="类索引、父类索引与接口索引"><a href="#类索引、父类索引与接口索引" class="headerlink" title="类索引、父类索引与接口索引"></a>类索引、父类索引与接口索引</h2><p>类索引和父类索引都是一个u2类型的数据，而接口索引集合是一组u2类型的数据集合。Class文件中由这三项数据来确定该类型的继承关系。索引引用于确定这个类的全限定名，父类索引用于确定这个类的父类的全限定名，除java.lang.Object之外，所有Java类的父类索引都不为0。</p>
<p>类索引、父类索引和接口索引集合都按照顺序排列在访问标志之后，类索引和父类索引，引用两个u2类型的索引值表示，他们各自指向一个类型的CONSTANT_Class_info的类描述符常量。通过CONSTANT_Class_info类型的常量中的全限定名字符串。接口入口引入一个u2类型的数据为接口计数器，表示索引表容量。如果没有实现任何接口，计数器值为0，索引表不再占用任何字节。</p>
<h2 id="字段表集合"><a href="#字段表集合" class="headerlink" title="字段表集合"></a>字段表集合</h2><p>用于描述接口或类中声明的变量。包括类级变量及实例级变量，但不包括方法内部声明的局部变量。</p>
<p><strong>字段表结构</strong></p>
<table>
<thead>
<tr>
<th>类型</th>
<th>名称</th>
<th>数量</th>
</tr>
</thead>
<tbody><tr>
<td>u2</td>
<td>access_flags</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>name_index</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>description_index</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>attributes_count</td>
<td>1</td>
</tr>
<tr>
<td>attribute_info</td>
<td>attributes</td>
<td>attributes_count</td>
</tr>
</tbody></table>
<p><strong>access_flags（字段访问标志）</strong></p>
<table>
<thead>
<tr>
<th>标志名称</th>
<th>标志值</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>ACC_PUBLIC</td>
<td>0x0001</td>
<td>字段是否为public</td>
</tr>
<tr>
<td>ACC_PRIVATE</td>
<td>0x0002</td>
<td>字段是否为private</td>
</tr>
<tr>
<td>ACC_PROTECTED</td>
<td>0x0004</td>
<td>字段是否为protected</td>
</tr>
<tr>
<td>ACC_STATIC</td>
<td>0x0008</td>
<td>字段是否是static</td>
</tr>
<tr>
<td>ACC_FINAL</td>
<td>0x0010</td>
<td>字段是否final</td>
</tr>
<tr>
<td>ACC_VOLATILE</td>
<td>0x0040</td>
<td>字段是否volatile</td>
</tr>
<tr>
<td>ACC_TRANSIENT</td>
<td>0x0080</td>
<td>字段是否transient</td>
</tr>
<tr>
<td>ACC_SYNTHETIC</td>
<td>0x0100</td>
<td>字段是否由编译器自动产生</td>
</tr>
<tr>
<td>ACC_ENUM</td>
<td>0x0400</td>
<td>字段是否enum</td>
</tr>
</tbody></table>
<p><strong>全限定名：</strong>包含包路径，使用/分割目录。</p>
<p><strong>简单名称（name_index）：</strong>描述方法或字段的名称。</p>
<p><strong>描述符（description_index）：</strong>描述字段的数据类型、方法的参数列表和返回值。</p>
<p><strong>描述符字段描述方式</strong></p>
<table>
<thead>
<tr>
<th>表示字符</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>B</td>
<td>基本类型byte</td>
</tr>
<tr>
<td>C</td>
<td>基本类型char</td>
</tr>
<tr>
<td>D</td>
<td>基本类型double</td>
</tr>
<tr>
<td>F</td>
<td>基本类型float</td>
</tr>
<tr>
<td>I</td>
<td>基本类型int</td>
</tr>
<tr>
<td>J</td>
<td>基本类型long</td>
</tr>
<tr>
<td>S</td>
<td>基本类型short</td>
</tr>
<tr>
<td>Z</td>
<td>基本类型boolean</td>
</tr>
<tr>
<td>V</td>
<td>特殊类型void</td>
</tr>
<tr>
<td>L</td>
<td>对象类型，如Ljava/lang/Object;</td>
</tr>
</tbody></table>
<p>数组类型，每一维度将使用一个前置的“[”字符来描述，如一个定义为“java.lang.String[][]”类型的二维数组，将被记录成“[[Ljava/lang/String;”一个整型数组int[]将被记录成“[I”。</p>
<p><strong>描述符方法描述方式</strong></p>
<p>按照先参数列表、后返回值的顺序描述，如方法void inc() 的描述符为“()V”，方法java/lang/String  toString()的描述符为“()Ljava/lang/String;”，方法int  index(char[] source,int sourceOffset,int sourceCount,char[] target,int targetOffset,int tartgetCount,int fromIndex)的描述符为“([CII[CII)I”。</p>
<p><strong>Java语言中，两个字段的数据类型、修饰符不管是否相同，都必须使用不一样的名称，但Class文件格式来讲，只要两个字段描述符不是完全相同，那字段重名是合法的。</strong></p>
<h2 id="方法表集合"><a href="#方法表集合" class="headerlink" title="方法表集合"></a>方法表集合</h2><p><strong>方法表结构</strong></p>
<table>
<thead>
<tr>
<th>类型</th>
<th>名称</th>
<th>数量</th>
</tr>
</thead>
<tbody><tr>
<td>u2</td>
<td>access_flags</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>name_index</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>description_index</td>
<td>1</td>
</tr>
<tr>
<td>u2</td>
<td>attributes_count</td>
<td>1</td>
</tr>
<tr>
<td>attribute_info</td>
<td>attributes</td>
<td>attributes_count</td>
</tr>
</tbody></table>
<p><strong>access_flags（方法访问标志）</strong></p>
<table>
<thead>
<tr>
<th>标志名称</th>
<th>标志值</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>ACC_PUBLIC</td>
<td>0x0001</td>
<td>方法是否为public</td>
</tr>
<tr>
<td>ACC_PRIVATE</td>
<td>0x0002</td>
<td>方法是否为private</td>
</tr>
<tr>
<td>ACC_PROTECTED</td>
<td>0x0004</td>
<td>方法是否为protected</td>
</tr>
<tr>
<td>ACC_STATIC</td>
<td>0x0008</td>
<td>方法是否是static</td>
</tr>
<tr>
<td>ACC_FINAL</td>
<td>0x0010</td>
<td>方法是否final</td>
</tr>
<tr>
<td>ACC_SYNCHRONIZED</td>
<td>0x0020</td>
<td>方法是否synchronized</td>
</tr>
<tr>
<td>ACC_BRIDGE</td>
<td>0x0040</td>
<td>方法是不是由编译器产生的桥接方法</td>
</tr>
<tr>
<td>ACC_VARARGS</td>
<td>0x0080</td>
<td>方法是否接收不定参数</td>
</tr>
<tr>
<td>ACC_NATIVE</td>
<td>0x1000</td>
<td>方法是否为native</td>
</tr>
<tr>
<td>ACC_ABSTRACT</td>
<td>0x0400</td>
<td>方法是否是abstract</td>
</tr>
<tr>
<td>ACC_STRICT</td>
<td>0x0800</td>
<td>方法是否为strictfp</td>
</tr>
<tr>
<td>ACC_SYNTHETIC</td>
<td>0x1000</td>
<td>方法是否由编译器自动产生</td>
</tr>
</tbody></table>
<h2 id="属性表集合"><a href="#属性表集合" class="headerlink" title="属性表集合"></a><a href="https://acexxs.gitee.io/blog-page/2021/11/01/8005f5c53691.html">属性表集合</a></h2><p>Class文件、字段表、方法表都可以携带自己的属性表集合，以描述某些场景专有信息。</p>
<p><strong>虚拟机规范预定义的属性</strong></p>
<table>
<thead>
<tr>
<th>属性名称</th>
<th>使用位置</th>
<th>含义</th>
<th>版本</th>
</tr>
</thead>
<tbody><tr>
<td>Coder</td>
<td>方法表</td>
<td>Java代码编译成的字节码指令</td>
<td></td>
</tr>
<tr>
<td>ConstantValue</td>
<td>字段表</td>
<td>由final关键字定义的变量值</td>
<td></td>
</tr>
<tr>
<td>Deprecated</td>
<td>类、方法表、字段表</td>
<td>被声明为deprecated的方法和字段</td>
<td></td>
</tr>
<tr>
<td>Exceptions</td>
<td>方法表</td>
<td>方法抛出的异常列表</td>
<td></td>
</tr>
<tr>
<td>EnclosingMethod</td>
<td>类文件</td>
<td>仅当一个类为局部类或匿名类时才能拥有这个属性，这个属性用于标示这个类所在的外围方法</td>
<td></td>
</tr>
<tr>
<td>InnerClasses</td>
<td>类文件</td>
<td>内部类列表</td>
<td></td>
</tr>
<tr>
<td>LineNumberTable</td>
<td>Code属性</td>
<td>Java源码的行号与字节码指令的对应关系</td>
<td></td>
</tr>
<tr>
<td>LocalVariableTable</td>
<td>Code属性</td>
<td>方法的局部变量描述</td>
<td></td>
</tr>
<tr>
<td>StackMapTable</td>
<td>Code属性</td>
<td>供新的类型检查验证器（Type Checker）检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配</td>
<td>6</td>
</tr>
<tr>
<td>Signature</td>
<td>类、方法表、字段表</td>
<td>支持泛型情况下的方法签名，在Java语言中，任何类、接口、初始化方法或成员的泛型签名如果包含了类型变量（Type Variables）或参数化类型（Parameterized Types），则Signature属性会它记录泛型签名信息，由于Java的泛型采取擦出法实现，为了避免类型信息被擦除后导致签名混乱，需要这个属性记录泛型中的相关信息</td>
<td>5</td>
</tr>
<tr>
<td>SourceFile</td>
<td>类文件</td>
<td>记录源文件名称</td>
<td></td>
</tr>
<tr>
<td>SourceDebugExtension</td>
<td>类文件</td>
<td>存储额外调试信息（如JSP调试)</td>
<td>5</td>
</tr>
<tr>
<td>Synthetic</td>
<td>类、方法表、字段表</td>
<td>标识方法或字段编译器自动生成的</td>
<td></td>
</tr>
<tr>
<td>LocalVariableTypeTable</td>
<td>类</td>
<td>使用特征签名代替描述符，是为了引入泛型语法后，能描述泛型参数化类型而添加</td>
<td>5</td>
</tr>
<tr>
<td>RuntimeVisibleAnnotations</td>
<td>类、方法表、字段表</td>
<td>为动态注解提供支持，该属性用于指明哪些注解时运行时（时间上运行时就是进行反射调用时）可见的</td>
<td>5</td>
</tr>
<tr>
<td>RuntimeInvisibleAnnotations</td>
<td>类、方法表、字段表</td>
<td>与RuntimeVisibleAnnotations属性作用刚好相反，用于指明哪些注解是运行时不可见的</td>
<td>5</td>
</tr>
<tr>
<td>RuntimeVisibleParameterAnnotations</td>
<td>方法表</td>
<td>作用与RuntimeVisibleAnnotations属性类似，只不过作用对象为方法参数</td>
<td>5</td>
</tr>
<tr>
<td>RuntimeInvisibleParameterAnnotations</td>
<td>方法表</td>
<td>作用与RuntimeInvisibleAnnotations类似，只不过作用对象是方法参数</td>
<td>5</td>
</tr>
<tr>
<td>AnnotationDefault</td>
<td>方法表</td>
<td>用于记录注解类原色默认值</td>
<td>5</td>
</tr>
<tr>
<td>BootstrapMethod</td>
<td>类文件</td>
<td>用于保存invokedynamic指令引用的引导方法限定符</td>
<td>7</td>
</tr>
<tr>
<td>RuntimeVisibleTypeAnnotations</td>
<td>类、方法表、字段表</td>
<td>为实现JSR 308中新增的类型注解提供支持，用于指明哪些类注解是运行时可见的</td>
<td>8</td>
</tr>
<tr>
<td>RuntimeInvisibleTypeAnnotations</td>
<td>类、方法表、字段表</td>
<td>与RuntimeVisibleTypeAnnotations作用相反，用于指明哪些注解是运行时不可见的。</td>
<td>8</td>
</tr>
<tr>
<td>MethodParameters</td>
<td>方法表</td>
<td>用于支持（编译时加上-parameters参数）将方法名称编译进Class文件中，并可运行时获取，此前需要获取方法名称</td>
<td>8</td>
</tr>
<tr>
<td>Moudle</td>
<td>类</td>
<td>记录一个Module名称以及相关信息（require、exports、opens、uses、provides）</td>
<td>9</td>
</tr>
<tr>
<td>MoudlePackages</td>
<td>类</td>
<td>用于记录一个模块中所有被exports或者opens的包</td>
<td>9</td>
</tr>
<tr>
<td>MoudleMainClass</td>
<td>类</td>
<td>用于指定一个模块的主类</td>
<td>9</td>
</tr>
<tr>
<td>NestHost</td>
<td>类</td>
<td>用于支持嵌套类的反射和访问控制API，一个内部类通过该属性得知自己的宿主类</td>
<td>11</td>
</tr>
<tr>
<td>NestMembers</td>
<td>类</td>
<td>用于支持嵌套类的反射和访问控制的API，一个宿主类通过该属性得知自己由哪些内部类</td>
<td>11</td>
</tr>
</tbody></table>
<p><em><strong>每个属性，它的名称都要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示。属性值结构则是完全自定义的，只需要通过一个u4的长度属性去说明属性值所占用的位数即可。</strong></em></p>
<p><strong>符合规范的属性表结构</strong></p>
<table>
<thead>
<tr>
<th>类型</th>
<th>名称</th>
<th>数量</th>
</tr>
</thead>
<tbody><tr>
<td>u2</td>
<td>attribute_name_index</td>
<td>1</td>
</tr>
<tr>
<td>u4</td>
<td>attribute_length</td>
<td>1</td>
</tr>
<tr>
<td>u1</td>
<td>info</td>
<td>attribute_length</td>
</tr>
</tbody></table>
<h1 id="字节码指令"><a href="#字节码指令" class="headerlink" title="字节码指令"></a>字节码指令</h1><p><strong>指令：</strong>有一个字节长度的、代表某种特定操作含义的数字（操作码）以及跟随其后的零至多个代表此操作所需的参数（操作数）构成。</p>
<h2 id="加载和存储指令"><a href="#加载和存储指令" class="headerlink" title="加载和存储指令"></a>加载和存储指令</h2><ul>
<li><p><strong>将局部变量加载到操作栈：</strong>iload、iload_&lt;n&gt;、lload、load_&lt;n&gt;、fload、fload_&lt;n&gt;、dload、dload_&lt;n&gt;、aload、aload_&lt;n&gt;</p>
</li>
<li><p><strong>将一个数值从操作数栈存储到局部变量表：</strong>istore、istore_&lt;n&gt;、lstore、lstore_&lt;n&gt;、fstore、fstore_&lt;n&gt;、dstore、dstore_&lt;n&gt;、astore、astore_&lt;n&gt;</p>
</li>
<li><p><strong>将一个常量加载到操作数栈：</strong>bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_&lt;i&gt;、lconst_&lt;l&gt;、fconst_&lt;f&gt;、dconst_&lt;d&gt;</p>
</li>
<li><p><strong>扩充局部变量表的访问索引的指令：</strong>wide</p>
</li>
</ul>
<h2 id="运算指令"><a href="#运算指令" class="headerlink" title="运算指令"></a>运算指令</h2><ul>
<li><strong>加法指令：</strong>iadd、ladd、fadd、dadd</li>
<li><strong>减法指令：</strong>isub、lsub、fsub、dsub</li>
<li><strong>乘法指令：</strong>imul、lmul、fmul、dmul</li>
<li><strong>除法指令：</strong>idiv、ldiv、fdiv、ddiv</li>
<li><strong>求余指令：</strong>irem、lrem、frem、drem</li>
<li><strong>取反指令：</strong>ineg、lneg、fneg、dneg</li>
<li><strong>位移指令：</strong>ishl、ishr、iushr、lshl、lshr、lushr</li>
<li><strong>按位或指令：</strong>ior、lor</li>
<li><strong>按位与指令：</strong>iand、land</li>
<li><strong>按位异或指令：</strong>ixor、lxor</li>
<li><strong>局部变量自增指令：</strong>iinc</li>
<li><strong>比较指令：</strong>dcmpg、dcmpl、fcmpg、fcmpl、lcmp</li>
</ul>
<h2 id="类型转换指令"><a href="#类型转换指令" class="headerlink" title="类型转换指令"></a>类型转换指令</h2><p><strong>宽化类型转换(安全转换)：</strong>int-&gt;long、int-&gt;float、int-&gt;double、long-&gt;float、long-&gt;double、float-&gt;double</p>
<p><strong>窄化类型转换：</strong>必须显式地使用转换指令来完成。（i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f。</p>
<h2 id="对象创建与访问指令"><a href="#对象创建与访问指令" class="headerlink" title="对象创建与访问指令"></a>对象创建与访问指令</h2><ul>
<li><strong>创建类实例地指令：</strong>new</li>
<li><strong>创建数组地指令：</strong>newarray、anewarray、multianewarray</li>
<li><strong>访问类字段（staic字段或者称为类变量）和实例字段的指令：</strong>getfield、putfield、getstatic、putstatic</li>
<li><strong>把一个数组元素加载到操作数栈的指令：</strong>baload、caload、saload、iaload、laload、faload、daload、aaload</li>
<li><strong>将以给操作数栈的值储存到数组元素中的指令：</strong>bastore、castore、satore、iastore、fastore、dastore、aastore</li>
<li><strong>取数组长度的指令：</strong>arraylength</li>
<li><strong>检查类实例类型的指令：</strong>instanceof、checkcast</li>
</ul>
<h2 id="操作数栈管理指令"><a href="#操作数栈管理指令" class="headerlink" title="操作数栈管理指令"></a>操作数栈管理指令</h2><ul>
<li><strong>将操作数栈的栈顶一个或两个元素出栈：</strong>pop、pop2</li>
<li><strong>赋值站定一个或两个数值并将复制值或双份复制值重新压入栈顶：</strong>dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2</li>
<li><strong>将栈最顶端两个数值互换：</strong>swap</li>
</ul>
<h2 id="控制转移指令"><a href="#控制转移指令" class="headerlink" title="控制转移指令"></a>控制转移指令</h2><ul>
<li><strong>条件分支：</strong>ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne</li>
<li><strong>复合条件分支：</strong>tableswitch、lookupswitch</li>
<li><strong>无条件分支：</strong>goto、goto_w、jsr、jsr_w、ret</li>
</ul>
<h2 id="方法调用和返回指令"><a href="#方法调用和返回指令" class="headerlink" title="方法调用和返回指令"></a>方法调用和返回指令</h2><ul>
<li><strong>invokevirtual指令：</strong>调用对象的实例方法。</li>
<li><strong>invokeinterface指令：</strong>调用接口方法，运行时搜索一个实现这个接口的方法对象。</li>
<li><strong>invokespecial指令：</strong>用于调用一些需要特殊处理的实例方法，包括实例初始化方法、私有方法和父类方法。</li>
<li><strong>invokestatic指令：</strong>用于调用类的静态方法</li>
<li><strong>invokedynamic指令：</strong>在运行时动态解析出调用点限定符索引用的方法。并执行该方法。</li>
</ul>
<h2 id="异常处理指令"><a href="#异常处理指令" class="headerlink" title="异常处理指令"></a>异常处理指令</h2><p><strong>athrow</strong>指令来实现显式抛出异常的操作。</p>
<h2 id="同步指令"><a href="#同步指令" class="headerlink" title="同步指令"></a>同步指令</h2><ul>
<li><strong>方法级的同步：</strong>虚拟机根据常量池是的方法表结构中的ACC_SYNCHRONIZED访问标志得知方法是否被声明为同步你方法。</li>
<li><strong>方法内部一段指令序列的同步（monitorenter、moinitorexit）：</strong>synchronized语句块表示一段指令集序列同步。无论方法是否正常结束，方法调用过程的每条monitorenter指令都必须有其对应的monitorexit指令。</li>
</ul>
<h1 id="公有设计，私有实现"><a href="#公有设计，私有实现" class="headerlink" title="公有设计，私有实现"></a>公有设计，私有实现</h1><p><strong>虚拟机实现加载Class文件并保持其中语义完整性的实现方案：</strong></p>
<ul>
<li>将输入的Java虚拟机代码在加载时或执行时翻译成另一种虚拟机指令集。</li>
<li>将输入Java虚拟机代码在加载时或执行时翻译成宿主机处理程序的本地指令集（即即时编译器代码生成技术）。</li>
</ul>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://acexxs.gitee.io/blog-page/2021/10/28/c045633ac839.html" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog-page/tags/Class/" rel="tag">Class</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog-page/tags/JVM/" rel="tag">JVM</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog-page/tags/Java/" rel="tag">Java</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/blog-page/2021/10/28/cd70ccfc5667.html" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            深入理解JVM（八）类加载机制
          
        </div>
      </a>
    
    
      <a href="/blog-page/2021/10/19/0eaed7906b18.html" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">深入理解JVM（六）虚拟机调优实战</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "4Gx0dzptNxW0Nb4xekYQLQF1-gzGzoHsz",
    app_key: "nvoM2TGGO7QpNlr3vAy3DQyg",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "欢迎一起探讨交流~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
     
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2021
        <i class="ri-heart-fill heart_icon"></i> ACEXS
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/blog-page/"><img src="/blog-page/images/ayer-side.svg" alt="ACEXS个人博客"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog-page/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/blog-page/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>表扬一下吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/blog-page/images/alipay.png">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/blog-page/images/wechat.png">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/blog-page/js/jquery-3.6.0.min.js"></script>
 
<script src="/blog-page/js/lazyload.min.js"></script>

<!-- Tocbot -->
 
<script src="/blog-page/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: ".tocbot",
    contentSelector: ".article-entry",
    headingSelector: "h1, h2, h3, h4, h5, h6",
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: "main",
    positionFixedSelector: ".tocbot",
    positionFixedClass: "is-position-fixed",
    fixedSidebarOffset: "auto",
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/blog-page/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->
 
<script src="/blog-page/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/blog-page/css/clipboard.css">
 <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->
 
<script src="/blog-page/js/dz.js"></script>
 
<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    

  </div>
</body>

</html>